MAX_VALUE = 99*60 + 59
TIMER_FREQUENCY = 15625
DELAY_SCHEMA1 = 100
DELAY_SCHEMA2 = 1000
DELAY_DISPLAY = 10

BUZZ = PORTC.4

ALED = PORTA.2
BLED = PORTC.0
CLED = PORTC.1
DLED = PORTC.2
ELED = PORTB.4
FLED = PORTB.5
GLED = PORTB.6

DIGIT1 = PORTC.5
DIGIT2 = PORTC.7
DIGIT3 = PORTC.6
DIGIT4 = PORTC.3

currentValue = 0
timerCount = 0
secElapsed = 0
oldElapsedMs = 0
oldPortA5 = 0
ringing = False
running = False

def init():
    TRISA = 0b00011011 # RA0, RA1, RA3, RA4 are input, RA2 is output ; RA0-1-3 used for ICSP. RA4 -> LSB rotary switch, RA5 -> 2LSB rotary switch
    TRISB = 0b10000000 # RB7 is input, rest are output ; RB7 -> start button
    TRISC = 0b00000000 # RC are output
    
    CONFIG1.FOSC<1:0> to 00 for internal clk
    CONFIG1.CLKOUTEN to 1 set CLKOUT as standard I/O
    OSCCON.IRCF<3:0> to select clock frequency (div of 16MHz) -> 1111 = 16MHz
    CONFIG1.BOREN<1:0> to 00 (no Brown-out reset)
    CONFIG1.MCLRE and CONFIG2.LVP to 1
    CONFIG1.PWRTE to 1 to disable power up timer (delay after power on before running)
    
    INTCON.IOCIE to 1
    IOCAP to 0x00010000 (bit 4 of PORT A detect rising edge)
    IOCAN to 0x00010000 (bit 4 of PORT A detect falling edge)
    IOCBP to 0x10000000 (bit 7 of PORT B detect rising edge)
    
    OPTION_REG.TMR0CS to 0 (timer0 in timer mode)
    OPTION_REG.PSA to 1 (no prescaler) timeout = 16M/4/256 = 15625Hz
    INTCON.TMR0IE to 1 (interrupt on timer0)

def main():
    init()
    
    while True:
        displayValue(currentValue)

def interrupt():
    if IOCAF.4:
        IOCAF.4 = 0
        # switch rotated
        
        elapsedMs = 1000*secElapsed + 1000*timerCount/MAX_VALUE # do not factorize the 1000* to prevent rounding
        
        diff = elapsedMs - oldElapsedMs
        
        oldElapsedMs = elapsedMs
        
        if diff < 1:
            value = 300
        elif diff < 10:
            value = 60
        elif diff < 50:
            value = 10
        elif diff < 100:
            value = 5
        else:
            value = 1
        
        if PORTA.4 and PORTA.5 != oldPortA5 and currentValue > 0:
            currentValue -= value
            
        elif PORTA.4 and PORTA.5 == oldPortA5 and currentValue < MAX_VALUE:
            currentValue += value
            
        elif not PORTA.4 and PORTA.5 != oldPortA5 and currentValue < MAX_VALUE:
            currentValue += value
            
        elif not PORTA.4 and PORTA.5 == oldPortA5 and currentValue > 0:
            currentValue -= value
        
        oldPortA5 = PORTA.5
        
        
    elif IOCBF.7:
        IOCBF.7 = 0
        # Start button
        ringing = False
        
        timerCount = 0
        running = !running
        
    elif INTCON.TMR0IF:
        INTCON.TMR0IF = 0
        # Timer0 overflow
        
        timerCount += 1
        
        if timerCount >= TIMER_FREQUENCY:
            timerCount = 0
            secElapsed += 1

            if running:
                currentValue -= 1
                if currentValue == 0:
                    ringing = True
                    playSound()

def playSound():
    while ringing:
        for i in range(4):
            BUZZ = 1
            delayMs(DELAY_SCHEMA1)
            BUZZ = 0
            delayMs(DELAY_SCHEMA1)
        delayMs(DELAY_SCHEMA2)

def displayValue(n):
    sec = n % 60
    min = n / 60
    
    showDigit(min/10, 1)
    delayMs(DELAY_DISPLAY)
    
    showDigit(min%10, 2)
    delayMs(DELAY_DISPLAY)
    
    showDigit(sec/10, 3)
    delayMs(DELAY_DISPLAY)
    
    showDigit(sec%10, 4)
    delayMs(DELAY_DISPLAY)

def showDigit(value, digit):
    DIGIT1 = 0
    DIGIT2 = 0
    DIGIT3 = 0
    DIGIT4 = 0
    if digit == 1:
        DIGIT1 = 1
    elif digit == 2:
        DIGIT2 = 1
    elif digit == 3:
        DIGIT3 = 1
    else:
        DIGIT4 = 1
    
    ALED = 0
    BLED = 0
    CLED = 0
    DLED = 0
    ELED = 0
    FLED = 0
    GLED = 0
    if value == 1:
        BLED = 1
        CLED = 1
    elif value == 2:
        ALED = 1
        BLED = 1
        GLED = 1
        ELED = 1
        DLED = 1
    elif value == 3:
        ALED = 1
        BLED = 1
        GLED = 1
        CLED = 1
        DLED = 1
    elif value == 4:
        FLED = 1
        GLED = 1
        BLED = 1
        CLED = 1
    elif value == 5:
        ALED = 1
        FLED = 1
        GLED = 1
        CLED = 1
        DLED = 1
    elif value == 6:
        ALED = 1
        CLED = 1
        DLED = 1
        ELED = 1
        FLED = 1
        GLED = 1
    elif value == 7:
        ALED = 1
        BLED = 1
        CLED = 1
    elif value == 8:
        ALED = 1
        BLED = 1
        CLED = 1
        DLED = 1
        ELED = 1
        FLED = 1
        GLED = 1
    elif value == 9:
        ALED = 1
        BLED = 1
        CLED = 1
        DLED = 1
        FLED = 1
        GLED = 1
    elif value == 0:
        ALED = 1
        BLED = 1
        CLED = 1
        DLED = 1
        ELED = 1
        FLED = 1
    

